#include "crivo.h"
	#include <string.h>
	#include <omp.h>

	#define TOTAL_CHARS 50000
	#define TOTAL_WORDS 20000
	#define FILE_NAME "wikipedia.txt"
	#define MIN_THREADS 1

	int palindrome_word(char *);
	void clean_tokens(char [][25], int *);
	int bline(char **, char *);
	int fsize(char *);

	int main (int argc, char *argv[]) {

	  int totalw = 0, totalprime = 0, auxtotalw = 0, auxtotalprime = 0, bsize, nthreads;
	  double tstart, tend;
	  char fname[30];

	  strcpy(fname, (argc > 1 && argv[1] != NULL) ? argv[1] : FILE_NAME);
	  nthreads = ((argc > 2 && argv[2] != NULL) ? atoi(argv[2]) : MIN_THREADS);

	  bsize = fsize(fname)/nthreads;

	  omp_set_num_threads(nthreads);
	  tstart = omp_get_wtime();

	  #pragma omp parallel firstprivate(bsize, auxtotalw, auxtotalprime) reduction (+: totalw, totalprime)
	  {
	    char tokens[TOTAL_WORDS][25], line[TOTAL_CHARS];
	    int ntokens = 0, i;

	    FILE *f;
	    char *block = (char*) calloc(bsize+1, sizeof(char));

	    if (!(f = fopen(fname, "r")) || fseek(f, bsize*omp_get_thread_num(), SEEK_SET) ||
	        !fread(block, sizeof(char), bsize, f))
	      exit(1);

	    bline(&block, line);

	    do {

	      char *token, *rest, *ptr = line;

	      while((token = strtok_r(ptr, " ,.-()", &rest))) {
	        strcpy(tokens[ntokens], token);
	        ntokens++;
	        ptr = rest;
	      }

	      for(i=0 ; i<ntokens ; i++)
	        if(palindrome_word(tokens[i])) {
	          auxtotalw++;
	          if(prime_word(tokens[i]))
	            auxtotalprime++;
	        }

	      clean_tokens(tokens, &ntokens);

	    } while(bline(&block, line));

	    fclose(f);

	    #pragma omp barrier
	    #pragma omp critical
	    tend = omp_get_wtime();

	    totalw += auxtotalw;
	    totalprime += auxtotalprime;
	  }

	  printf("Total de palavras palindromes: %d\n", totalw);
	  printf("Total de palavras palindromes e primas: %d\n", totalprime);
	  printf("Tempo total: %f\n", tend-tstart);

	  return 0;
	}

	int palindrome_word(char *str) {

	  int size, i, j, palindrome = 1;

	  size = strlen(str);

	  if(size > 1)
	    for(i=0, j=size-1; i < size ; i++, j--)
	      palindrome = palindrome && (str[i] == str[j]);
	  else
	    palindrome = 0;

	  return palindrome;

	}

	void clean_tokens(char tokens[][25], int *n_tokens) {

	  int i;

	  for(i=0; i<40 ;i++)
	    strcpy(tokens[i], "");

	  *n_tokens = 0;

	}

	int bline(char **block, char *str) {

	  char c, aux[TOTAL_CHARS] = "";
	  int i = 0;

	  c = **block, (*block)++;

	  if(c != '\0') {
	    while((int)c != 13 && c != '\n' && c != '\0') {
	      if((int)c != 9)
	        aux[i] = c, i++;
	      else
	        aux[i] = ' ', i++;
	      c = **block, (*block)++;
	    }

	    strcpy(str, aux);

	    return 1;
	  } else
	    return 0;

	}

	int fsize(char *fname) {

	  int size;
	  FILE *f;

	  if(!(f = fopen(fname, "r")) || fseek(f, 0, SEEK_END) || !(size = ftell(f)))
	    exit(1);

	  return size;
	}
